package com.ganzi.manager.activiti.service.imp;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.ganzi.manager.activiti.request.ModelerRequest;
import com.ganzi.manager.activiti.request.PublishRequest;
import com.ganzi.manager.activiti.request.SaveModelRequest;
import com.ganzi.manager.activiti.service.ModelerService;
import org.activiti.bpmn.BpmnAutoLayout;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.Model;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.validation.ProcessValidator;
import org.activiti.validation.ProcessValidatorFactory;
import org.activiti.validation.ValidationError;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.ganzi.manager.activiti.util.ActivitiUtil.*;

@Service
public class ModelerServiceImp implements ModelerService{
    private static final Logger logger = LoggerFactory.getLogger(ModelerServiceImp.class);

    @Resource
    private RepositoryService repositoryService;
    @Resource
    private ObjectMapper objectMapper;
    @Resource
    private HistoryService historyService;
    @Resource
    private RuntimeService runtimeService;

    /**
     * 获取创建的模型
     * */
    @Override
    public Map<String, Object> getModelList() {
        Map<String, Object> result = new HashMap<>();
        result.put("code", "SUCCESS");
        result.put("data",repositoryService.createModelQuery().list());
        return result;
    }

    /**
     * 发布
     * */
    @Override
    public Map<String, Object> publish(PublishRequest publishModelerRequest, boolean isActivitiJson) {
        Map<String, Object> map = new HashMap<>();
        try {
            Model modelData = repositoryService.getModel(publishModelerRequest.getModelId());
            byte[] bytes = repositoryService.getModelEditorSource(modelData.getId());
            if (bytes == null) {
                logger.info("部署ID:{}的模型数据为空，请先设计流程并成功保存，再进行发布",publishModelerRequest.getModelId());
                map.put("code", "FAILURE");
                map.put("msg", "模型数据为空");
                return map;
            }
            //json转BpmnModel
            BpmnModel model;
            if(isActivitiJson){
                //activit的json格式
                model = converterActivitiJsonToBpmn(bytes);
            }else{
                //自定义的json格式
                model = converterJsonToBpmn(bytes);
            }
            if(model != null){
                //自动布局
                new BpmnAutoLayout(model).execute();
                Deployment deployment = repositoryService.createDeployment()
                        .name(modelData.getName())
                        .addBpmnModel(modelData.getKey()+".bpmn20.xml", model)
                        .deploy();
                modelData.setDeploymentId(deployment.getId());
                repositoryService.saveModel(modelData);
                map.put("code", "SUCCESS");
                map.put("msg", "发布成功");
            }else{
                map.put("code", "FAILURE");
                map.put("msg", "发布失败，模型结构错误");
            }
        } catch (Exception e) {
            logger.info("部署modelId:{}模型服务异常：{}",publishModelerRequest.getModelId(),e);
            map.put("code", "FAILURE");
            map.put("msg", "服务异常");
        }
        logger.info("流程部署出参map：{}",map);
        return map;
    }

    /**
     * 撤回
     * */
    @Override
    public Map<String, Object> revokePublish(PublishRequest publishModelerRequest) {
        logger.info("撤销发布流程入参modelId：{}",publishModelerRequest.getModelId());
        Map<String, Object> map = new HashMap<>();
        Model modelData = repositoryService.getModel(publishModelerRequest.getModelId());
        if(null != modelData){
            try {
                /**
                 * 参数不加true:为普通删除，如果当前规则下有正在执行的流程，则抛异常
                 * 参数加true:为级联删除,会删除和当前规则相关的所有信息，包括历史
                 */
                repositoryService.deleteDeployment(modelData.getDeploymentId(),true);
                map.put("code", "SUCCESS");
                map.put("msg", "撤销成功");
            } catch (Exception e) {
                logger.error("撤销已部署流程服务异常：{}",e);
                map.put("code", "FAILURE");
                map.put("msg", "撤销失败");
            }
        }
        logger.info("撤销发布流程出参map：{}",map);
        return map;
    }

    /**
     * 删除Model
     * */
    @Override
    public Map<String, Object> deleteModel(PublishRequest publishModelerRequest) {
        logger.info("删除流程实例入参modelId：{}",publishModelerRequest.getModelId());
        Map<String, Object> map = new HashMap<>();
        Model modelData = repositoryService.getModel(publishModelerRequest.getModelId());
        if(null != modelData){
            try {
                ProcessInstance pi = runtimeService.createProcessInstanceQuery().processDefinitionKey(modelData.getKey()).singleResult();
                if(null != pi) {
                    runtimeService.deleteProcessInstance(pi.getId(), "");
                    historyService.deleteHistoricProcessInstance(pi.getId());
                }
                //删除模型
                repositoryService.deleteModel(publishModelerRequest.getModelId());
                //删除发布，如果是true 表示强制删除，会删除正在执行的流程
                repositoryService.deleteDeployment(modelData.getDeploymentId(),true);
                map.put("code", "SUCCESS");
                map.put("msg", "删除成功");
            } catch (Exception e) {
                logger.error("删除流程实例服务异常：{}",e);
                map.put("code", "FAILURE");
                map.put("msg", "删除失败");
            }
        }
        logger.info("删除流程实例出参map：{}",map);
        return map;
    }

    /**
     * 编辑模型（设计的时候，数据库存放的是自定义json）
     * */
    @Override
    public Map<String, Object> editModel(PublishRequest publishRequest, boolean isActivitiJson) {
        Map<String, Object> map = new HashMap<>();
        try {
            Map<String, Object> dataMap = new HashMap<>();
            if(publishRequest != null && StringUtils.isNotBlank(publishRequest.getModelId())){
                Model modelData = repositoryService.getModel(publishRequest.getModelId());
                if(modelData != null){
                    byte[] bytes = repositoryService.getModelEditorSource(modelData.getId());
                    String json;
                    if(isActivitiJson){
                        //activit标准json 跟 自定义json 需要相互转换
                        String temp = new String(bytes,"UTF-8");
                        json = converterJsonToActivitiJson(temp);
                    }else{
                        json = new String(bytes,"UTF-8");
                    }
                    dataMap.put("model",modelData);
                    dataMap.put("json",json);
                }
            }
            map.put("data", dataMap);
            map.put("code", "SUCCESS");
        } catch (Exception e) {
            e.printStackTrace();
            map.put("code", "FAILURE");
            map.put("msg", "服务器异常");
        }
        return map;
    }

    /**
     * 验证模型
     * */
    @Override
    public Map<String, Object> cheakModel(PublishRequest publishModelerRequest, boolean isActivitiJson) {
        Map<String, Object> map = new HashMap<>();
        try{
            if(publishModelerRequest != null && StringUtils.isNotBlank(publishModelerRequest.getModelId())){
                Model modelData = repositoryService.getModel(publishModelerRequest.getModelId());
                byte[] bytes = repositoryService.getModelEditorSource(modelData.getId());
                BpmnModel model;
                if(isActivitiJson){
                    model = converterActivitiJsonToBpmn(bytes);
                }else{
                    model = converterJsonToBpmn(bytes);
                }
                if(model != null){
                    //验证bpmnModel 是否是正确的bpmn xml文件
                    ProcessValidatorFactory processValidatorFactory=new ProcessValidatorFactory();
                    ProcessValidator defaultProcessValidator = processValidatorFactory.createDefaultProcessValidator();
                    //验证失败信息的封装ValidationError
                    List<ValidationError> validate = defaultProcessValidator.validate(model);
                    System.out.println(validate.size());
                    if(validate.size()>0)System.out.println(validate.get(0).getProblem());
                }else{
                    map.put("code", "FAILURE");
                    map.put("msg", "模型中属性错误");
                }
            }else{
                map.put("code", "FAILURE");
                map.put("msg", "模型不存在");
            }
        }catch (Exception e){
            e.printStackTrace();
            map.put("code", "FAILURE");
            map.put("msg", "服务器异常");
        }
        return map;
    }


    /**
     * 保存模型
     * */
    @Override
    public Map<String, Object> saveModel(SaveModelRequest saveModelRequest, boolean isActivitiJson) {
        Map<String, Object> map = new HashMap<>();
        try {
            if(saveModelRequest !=null && StringUtils.isNotBlank(saveModelRequest.getKey())&& StringUtils.isNotBlank(saveModelRequest.getJson())
                    && StringUtils.isNotBlank(saveModelRequest.getName())){
                Model modelData;
                if(StringUtils.isNotBlank(saveModelRequest.getModelId())){
                    modelData = repositoryService.getModel(saveModelRequest.getModelId());
                    modelData.setMetaInfo(saveModelRequest.getMetaInfo());
                }else{
                    modelData = creatBaseModel(saveModelRequest.getName(),saveModelRequest.getKey());
                }
                repositoryService.saveModel(modelData);
                String json_xml;
                if(isActivitiJson){
                    //activit标准json 跟 自定义json 需要相互转换
                    json_xml = converterActivitiJsonToJson(saveModelRequest.getJson());
                }else{
                    json_xml = saveModelRequest.getJson();
                }
                repositoryService.addModelEditorSource(modelData.getId(), json_xml.getBytes("utf-8"));
                map.put("code", "SUCCESS");
            }
            map.put("code", "FAILURE");
            map.put("msg", "模型数据不能为空！");
        } catch (Exception e) {
            e.printStackTrace();
            map.put("code", "FAILURE");
            map.put("msg", "服务器异常");
        }
        return map;
    }

    /**
     * 创建空的模型-------------提供activitModeler使用
     * */
    @Override
    public Map<String, Object> create(ModelerRequest modelerRequest) {
        Map<String, Object> result = new HashMap<>();
        Model model = creatBaseModel(modelerRequest.getName(), modelerRequest.getKey());
        createObjectNode(model.getId());
        logger.info("创建模型结束，返回模型ID：{}",model.getId());
        result.put("code", "SUCCESS");
        result.put("msg", "创建成功");
        result.put("data", model.getId());
        return result;
    }
    private Model creatBaseModel(String name,String key){
        Model model = repositoryService.newModel();
        ObjectNode modelNode = objectMapper.createObjectNode();
        modelNode.put(ModelDataJsonConstants.MODEL_NAME, name);
        modelNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, "");
        modelNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);
        model.setName(name);
        model.setKey(key);
        model.setMetaInfo(modelNode.toString());
        repositoryService.saveModel(model);
        return model;
    }
    private void createObjectNode(String modelId){
        logger.info("创建模型完善ModelEditorSource入参模型ID：{}",modelId);
        ObjectNode editorNode = objectMapper.createObjectNode();
        editorNode.put("id", "canvas");
        editorNode.put("resourceId", "canvas");
        ObjectNode stencilSetNode = objectMapper.createObjectNode();
        stencilSetNode.put("namespace","http://b3mn.org/stencilset/bpmn2.0#");
        editorNode.put("stencilset", stencilSetNode);
        try {
            repositoryService.addModelEditorSource(modelId,editorNode.toString().getBytes("utf-8"));
        } catch (Exception e) {
            logger.info("创建模型时完善ModelEditorSource服务异常：{}",e);
        }
        logger.info("创建模型完善ModelEditorSource结束");
    }



}
